/**
  ******************************************************************************
  * @file   w25qxx.c  
  * @brief   
  * @author Peter
  * @version V0.0.2
  * @date 2022/08/15
  ******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "dev_w25qxx.h"


/* Private defines ---------------------------------------------------------------*/
#define SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE	 0

/* command table defines  ---------------------------------------------------------*/
#define W25X_WRITEENABLE			0X06
#define W25X_WRITEDISABLE			0X04
#define W25X_READSTATUSREG		    0X05
#define W25X_WRITESTATUSREG		    0X01
#define W25X_READDATA			 	0X03
#define W25X_FASTREADDATA			0X0B
#define W25X_FASTREADDUAL			0X3B
#define W25X_PAGEPROGRAM			0X02
#define W25X_BLOCKERASE				0XD8
#define W25X_SECTORERASE			0X20
#define W25X_CHIPERASE				0XC7
#define W25X_POWERDOWN				0XB9
#define W25X_RELEASEPOWERDOWN		0XAB
#define W25X_DEVICEID				0XAB
#define W25X_MANUFACTDEVICEID		0X90
#define W25X_JEDECDEVICEID			0X9F


/* Private Struct ---------------------------------------------------------------*/

/* Private enum ---------------------------------------------------------------*/
typedef enum {
	W25Q80_MBYTE  = 8,
	W25Q16_MBYTE  = 16,
	W25Q32_MBYTE  = 32,
	W25Q64_MBYTE  = 64,
	W25Q128_MBYTE = 128,
}w25qxx_capacity_e;
/* Private Variable ---------------------------------------------------------------*/

//Pointer

//Array

//Const

/* Private function prototypes -----------------------------------------------*/
/***********************************************************************************
 * @brief 初始化SPI FLASH的IO口
 * ex:      4Kbytes为一个Sector  16个扇区为1个Block
 * @par 
 * None
 * @retval void None
 **********************************************************************************/


/***********************************************************************************
 * @brief  读取W25QXX的状态寄存器
 * ex: 		 BIT7  6   5   4   3   2   1   0
 * @par     
 * None
 * @retval SPR   RV  TB BP2 BP1 BP0 WEL BUSY
 **********************************************************************************/
uint8_t W25qxxReadSR(dev_w25qxx_t* this)
{
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1	
	uint8_t byte = 0;
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);												 						    //使能器件
	
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), W25X_READSTATUSREG);    //发送读取状态寄存器命令
	byte = this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), 0Xff);		    //读取一个字节
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);												 						    //取消片选
	
	return byte;
#else	
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);		
	
	byteWrite = W25X_READSTATUSREG;															//使能器件
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);  //发送读取状态寄存器命令
	byteWrite = 0xFF;
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);	//读取一个字节
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);														 //取消片选
	
	return byteRead;
#endif
}

/***********************************************************************************
 * @brief 等待空闲
 * ex: 		
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
static void W25qxxWaitBusy(dev_w25qxx_t* this)
{
	while ((W25qxxReadSR(this) & 0x01) == 0x01)
		; // 等待BUSY位清空
}
/***********************************************************************************
 * @brief 写W25QXX状态寄存器
 * ex: 		只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
void W25qxxWrite_SR(dev_w25qxx_t* this, uint8_t sr)
{
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);					//使能器件
	
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1	
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), W25X_SECTORERASE);  	//发送写取状态寄存器命令
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), sr);					//写入一个字节
#else	
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;
																						    
	byteWrite = W25X_SECTORERASE;							                                
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);  //发送写取状态寄存器命令
	byteWrite = sr;                                                                         
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);  //写入一个字节
#endif
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);                   //取消片选
}
/***********************************************************************************
 * @brief W25QXX写使能	
 * ex: 		将WEL置位 
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
static void W25qxxWriteEnable(dev_w25qxx_t* this)
{
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);				    //使能器件
	
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1	
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), W25X_WRITEENABLE);      //发送写使能
#else	
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;
	
	byteWrite = W25X_WRITEENABLE;														
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);  //发送写使能				
#endif	
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);					//取消片选
}
/***********************************************************************************
 * @brief W25QXX写禁止	
 * ex: 		将WEL清零 
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
void W25qxxWriteDisable(dev_w25qxx_t* this)
{
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);				//使能器件
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), W25X_WRITEDISABLE); 	//发送写禁止指令
#else	
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;
	
	byteWrite = W25X_WRITEDISABLE;	
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);  //发送写禁止指令	
#endif

	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);				//取消片选	
}

/***********************************************************************************
 * @brief  读取芯片ID
           返回值如下:				  
 * ex: 		 0XEF17,表示芯片型号为W25Q128 	
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
uint16_t W25qxxReadID(dev_w25qxx_t* this)
{
	uint16_t temp = 0;
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);					//使能器件
	
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1			
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), 0x90); 					//发送读取ID命令
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), 0x00);
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), 0x00);
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), 0x00);
	temp |= this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), 0xFF) << 8;
	temp |= this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), 0xFF);
#else		
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;

	byteWrite = 0x90;	
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);  //发送读取ID命令
	byteWrite = 0x00;
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);		
	byteWrite = 0x00;
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);
	byteWrite = 0x00;
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);	
	
	byteWrite = 0xFF;
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);
	temp |= byteRead << 8;
	byteWrite = 0xFF;
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);
	temp |= byteRead;				
#endif		

	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);					//取消片选
	return temp;
}

/***********************************************************************************
 * @brief  读取SPI FLASH  
 * ex: 		 在指定地址开始读取指定长度的数据
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
int W25qxxRead(dev_w25qxx_t* this, uint8_t *pbuffer, uint32_t readaddr, uint32_t numbytetoread)
{
	uint32_t i;
	
	if(readaddr + numbytetoread > this->private.mem_capacity_Byte)
		return -1;
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);						  //使能器件
	
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1		
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), W25X_READDATA);				  //发送读取命令
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), (uint8_t)((readaddr) >> 16)); //发送24bit地址
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), (uint8_t)((readaddr) >> 8));
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), (uint8_t)readaddr);
	for (i = 0; i < numbytetoread; i++)
	{
		pbuffer[i] = this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), 0XFF); 	  //循环读数
	}
#else		
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;
	
	byteWrite = W25X_READDATA;	                                                                  
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1); 		  //发送读取命令
	byteWrite = (uint8_t)((readaddr) >> 16);                                                      
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1); 		  //发送24bit地址	
	byteWrite = (uint8_t)((readaddr) >> 8);
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);
	byteWrite = (uint8_t)readaddr;
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);	
	
	byteWrite = 0XFF;
	for (i = 0; i < numbytetoread; i++)															  //循环读数
	{
		this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &pbuffer[i], 1);
	}
#endif	
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);				      	  //取消片选
	return 0;
}

/***********************************************************************************
 * @brief  SPI在一页(0~65535)内写入少于256个字节的数据
 * ex: 		 在指定地址开始写入最大256字节的数据
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
int W25qxxWritePage(dev_w25qxx_t* this, uint8_t *pbuffer, uint32_t writeaddr, uint32_t numbytetowrite)
{
	uint32_t i;
	
	if(writeaddr + numbytetowrite > this->private.mem_capacity_Byte || numbytetowrite > 256)
		return -1;	
	
	W25qxxWriteEnable(this);																		//SET WEL
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);							//使能器件
	
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1		
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), W25X_PAGEPROGRAM);				//发送写页命令
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), (uint8_t)((writeaddr) >> 16));  //发送24bit地址
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), (uint8_t)((writeaddr) >> 8));
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), (uint8_t)writeaddr);
	for (i = 0; i < numbytetowrite; i++)
	{
		this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), pbuffer[i]); 				//循环写数
	}
#else		
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;
	
	byteWrite = W25X_PAGEPROGRAM;	 
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1); 			//发送写页命令
	byteWrite = (uint8_t)((writeaddr) >> 16);
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1); 			//发送24bit地址	
	byteWrite = (uint8_t)((writeaddr) >> 8);
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);
	byteWrite = (uint8_t)writeaddr;
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);	
	
	for (i = 0; i < numbytetowrite; i++)
	{
		this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &pbuffer[i], &byteRead, 1);		//循环写数
	}
#endif	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);	 						//取消片选
	W25qxxWaitBusy(this);								 											//等待写入结束
	
	return 0;
}

/***********************************************************************************
 * @brief  无检验写SPI FLASH 
 * ex: 		 必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
int W25qxxWriteNoCheck(dev_w25qxx_t* this, uint8_t *pbuffer, uint32_t writeaddr, uint32_t numbytetowrite)
{
	uint32_t pageremain;
	
	if(writeaddr + numbytetowrite > this->private.mem_capacity_Byte)
		return -1;
	
	pageremain = 256 - writeaddr % 256; //单页剩余的字节数
	if (numbytetowrite <= pageremain)
		pageremain = numbytetowrite; //不大于256个字节
	while (1)
	{
		W25qxxWritePage(this, pbuffer, writeaddr, pageremain);
		if (numbytetowrite == pageremain)
			break; //写入结束了
		else		 //NumByteToWrite>pageremain
		{
			pbuffer += pageremain;
			writeaddr += pageremain;

			numbytetowrite -= pageremain; //减去已经写入了的字节数
			if (numbytetowrite > 256)
				pageremain = 256; //一次可以写入256个字节
			else
				pageremain = numbytetowrite; //不够256个字节了
		}
	}
	
	return 0;
}
/***********************************************************************************
 * @brief 
 * ex: 	擦除一个扇区 Dst_Addr:扇区地址 根据实际容量设置 擦除一个扇区的最少时间:150ms
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
int W25qxxEraseSector(dev_w25qxx_t* this, uint32_t dst_addr)
{
	if(dst_addr+1 > this->private.mem_capacity_Byte)
		return -1;
	
	dst_addr *= 4096;
	W25qxxWriteEnable(this); 																		//SET WEL
	W25qxxWaitBusy(this);	
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);							//使能器件
	
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1		
	//监视falsh擦除情况,测试用
	//printf("fe:%x\r\n",Dst_Addr);
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), W25X_SECTORERASE);			    //发送扇区擦除指令
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), (uint8_t)((dst_addr) >> 16));   //发送24bit地址
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), (uint8_t)((dst_addr) >> 8));
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), (uint8_t)dst_addr);	
#else
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;
	
	byteWrite = W25X_SECTORERASE;	 
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1); 		 	//发送扇区擦除指令
	byteWrite = (uint8_t)((dst_addr) >> 16);
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1); 			//发送24bit地址	
	byteWrite = (uint8_t)((dst_addr) >> 8);
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);
	byteWrite = (uint8_t)dst_addr;
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);	
#endif	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);	 						//取消片选
	W25qxxWaitBusy(this); 																			//等待擦除完成
	return 0;
}
/***********************************************************************************
 * @brief  擦除SPI FLASH  
 * ex: 		 在指定地址开始擦除指定长度的数据 
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
int W25qxxEraseAppointSector(dev_w25qxx_t* this, uint32_t writeaddr, uint32_t numbytetowrite)
{
	uint32_t secpos;
	uint32_t secoff;
	uint32_t secremain;

	if(writeaddr + numbytetowrite > this->private.mem_capacity_Byte)
		return -1;	
	
	//	/* 进入临界段，临界段可以嵌套 */
	//	taskENTER_CRITICAL();

	secpos = writeaddr / 4096; //扇区地址
	secoff = writeaddr % 4096; //在扇区内的偏移
	secremain = 4096 - secoff; //扇区剩余空间大小
	if (numbytetowrite <= secremain)
		secremain = numbytetowrite; //不大于4096个字节
	while (1)
	{
		W25qxxEraseSector(this, secpos); //擦除这个扇区

		if (numbytetowrite == secremain)
			break; //写入结束了
		else		 //写入未结束
		{
			secpos++;										 //扇区地址增1
			secoff = 0;									 //偏移位置为0
			numbytetowrite -= secremain; //字节数递减
			if (numbytetowrite > 4096)
				secremain = 4096; //下一个扇区还是写不完
			else
				secremain = numbytetowrite; //下一个扇区可以写完了
		}
	};

	//		/* 退出临界段 */
	//		taskEXIT_CRITICAL(  );
	
	return 0;
}
/***********************************************************************************
 * @brief  写SPI FLASH  
 * ex: 		 在指定地址开始写入指定长度的数据 
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
int W25qxxWrite(dev_w25qxx_t* this, uint8_t *pbuffer, uint32_t writeaddr, uint32_t numbytetowrite)
{
	uint32_t secpos;
	uint32_t secoff;
	uint32_t secremain;
	uint32_t i;
	uint8_t *W25QXX_BUF;
	secpos = writeaddr / 4096; //扇区地址
	secoff = writeaddr % 4096; //在扇区内的偏移
	secremain = 4096 - secoff; //扇区剩余空间大小
	
	if(writeaddr + numbytetowrite > this->private.mem_capacity_Byte)
		return -1;	
	
	if (numbytetowrite <= secremain)
		secremain = numbytetowrite; //不大于4096个字节
	while (1)
	{
		W25qxxRead(this, W25QXX_BUF, secpos * 4096, 4096); //读出整个扇区的内容
		for (i = 0; i < secremain; i++)							 //校验数据
		{
			if (W25QXX_BUF[secoff + i] != 0XFF)
				break; //需要擦除
		}
		if (i < secremain) //需要擦除
		{
			W25qxxEraseSector(this, secpos);			//擦除这个扇区
			for (i = 0; i < secremain; i++) //复制
			{
				W25QXX_BUF[i + secoff] = pbuffer[i];
			}
			W25qxxWriteNoCheck(this, W25QXX_BUF, secpos * 4096, 4096); //写入整个扇区
		}
		else
			W25qxxWriteNoCheck(this, pbuffer, writeaddr, secremain); //写已经擦除了的,直接写入扇区剩余区间.
		if (numbytetowrite == secremain)
			break; //写入结束了
		else		 //写入未结束
		{
			secpos++;										 //扇区地址增1
			secoff = 0;									 //偏移位置为0
			pbuffer += secremain;				 //指针偏移
			writeaddr += secremain;			 //写地址偏移
			numbytetowrite -= secremain; //字节数递减
			if (numbytetowrite > 4096)
				secremain = 4096; //下一个扇区还是写不完
			else
				secremain = numbytetowrite; //下一个扇区可以写完了
		}
	}
	
	return 0;
}
/***********************************************************************************
 * @brief 擦除整个芯片		  
 * ex: 		等待时间超长...
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
void W25qxxEraseChip(dev_w25qxx_t* this)
{
	W25qxxWriteEnable(this); 																//SET WEL
	W25qxxWaitBusy(this);

	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);					//使能器件
	
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1	
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), W25X_CHIPERASE); 		//发送片擦除命令
#else	
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;
	
	byteWrite = W25X_CHIPERASE;	 
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);  //发送片擦除命令
#endif	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);										 									//取消片选
	
	W25qxxWaitBusy(this);									 								//等待芯片擦除结束
}

/***********************************************************************************
 * @brief 进入掉电模式
 * ex: 		
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
void W25qxxPowerDown(dev_w25qxx_t* this)
{
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);					//使能器件
	
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1		
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), W25X_POWERDOWN); 		//发送掉电命令
#else	
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;

	byteWrite = W25X_POWERDOWN;	 
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);  //发送掉电命令
#endif	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);					//取消片选
	
	this->Delay_ms(3);												 						//等待TPD
}
/***********************************************************************************
 * @brief 唤醒
 * ex: 		
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
void W25qxxWakeUP(dev_w25qxx_t* this)
{
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);					//使能器件
	
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1	
	this->private.drv_spix.ReadWriteByte(&(this->private.drv_spix), W25X_RELEASEPOWERDOWN); //  send W25X_PowerDown command 0xAB
#else
	uint8_t byteRead = 0;
	uint8_t byteWrite = 0;
	
	byteWrite = W25X_RELEASEPOWERDOWN;	 
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1); 	//send W25X_PowerDown command 0xAB
#endif		
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);				   	//取消片选
		
	this->Delay_ms(3);																	   	//等待TRES1	
}
/***********************************************************************************
 * @brief //获取空闲标志
 * ex: 		
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
uint8_t W25qxxGetBusyFlag(dev_w25qxx_t* this)
{
	if ((W25qxxReadSR(this) & 0x01) == 0x01)
	{
		return true;
	}
	return false;
}

/***********************************************************************************
 * @brief W25qxx检查
 * ex:      
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
int W25qxxCheck(dev_w25qxx_t* this)
{
	//读取FLASH ID判断是否正确
	if(this->mem_type != W25qxxReadID(this))
		return -1;
	return 0;
}
/***********************************************************************************
 * @brief 初始化SPI FLASH的IO口
 * ex:      4Kbytes为一个Sector  16个扇区为1个Block
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
int Dev_W25qxxInitParamCheck(dev_w25qxx_t* this)
{
	//dev name check
//	if(this->DRV == NULL)
//		return -1;
	
	//SPI driver param check
	if(this->DRV == NULL || this->PIN_CS == NULL || this->PIN_SCK == NULL || this->PIN_MISO == NULL || this->PIN_MOSI == NULL)
		return -1;
	
	//delay func check
	if(this->Delay_ms == NULL)
		return -1;

	//capacity check, unit->Mbit
	uint8_t mem_capacity_MByte;
	switch(this->mem_type)
	{
		case W25Q80:
			mem_capacity_MByte = W25Q80_MBYTE;
			break;
		case W25Q16:
			mem_capacity_MByte = W25Q16_MBYTE;
			break;
		case W25Q32:
			mem_capacity_MByte = W25Q32_MBYTE;
			break;
		case W25Q64:
			mem_capacity_MByte = W25Q64_MBYTE;
			break;
		case W25Q128:
			mem_capacity_MByte = W25Q128_MBYTE;
			break;
		default:
			return -1;
	}
	this->private.mem_capacity_Byte = mem_capacity_MByte*1024*1024/8;
	return 0;
}
/***********************************************************************************
 * @brief 初始化SPI FLASH的IO口
 * ex:      4Kbytes为一个Sector  16个扇区为1个Block
 * @par 
 * None
 * @retval void None
 **********************************************************************************/
int Dev_W25qxxInit(dev_w25qxx_t* this)
{
	
	if(Dev_W25qxxInitParamCheck(this) < 0)
		return -1;
	
	//spi config
	this->private.drv_spix.DRV    	   			= this->DRV;
	this->private.drv_spix.PIN_CS      			= this->PIN_CS;
	this->private.drv_spix.PIN_MISO    			= this->PIN_MISO;
    this->private.drv_spix.PIN_MOSI    			= this->PIN_MOSI;
    this->private.drv_spix.PIN_SCK     			= this->PIN_SCK;											
	this->private.drv_spix.CS_EN       			= this->SPI_CS_MODE;
	this->private.drv_spix.SPEED	   			= this->SPI_SPEED;	
	this->private.drv_spix.ORDER       			= SPI_MSB;
	this->private.drv_spix.CPOL        			= SPI_CPOL_H;
	this->private.drv_spix.CPHA        			= SPI_CPHA_2;
	this->private.drv_spix.TRANS       			= SPI_TRANS_BYTE;
	this->private.drv_spix.CS_DELAY_US 			= 10;
	if(Drv_Spi_Init(&this->private.drv_spix) < 0){
        return -1;
    }
	
	//soft cs io config
	this->private.drv_gpio_spics.PIN 			= this->PIN_CS;
	this->private.drv_gpio_spics.MODE			= OUTPUT_UP;
	this->private.drv_gpio_spics.INIT_LEVEL 	= HIGHT_LEVEL;
	if(Drv_Gpio_Init(&this->private.drv_gpio_spics) < 0){
		return -1;
	}
	
	//wp io config
	if (this->PIN_WP != NULL)
	{
		this->private.drv_gpio_wp.PIN 			= this->PIN_WP;
		this->private.drv_gpio_wp.MODE			= OUTPUT_UP;
		this->private.drv_gpio_wp.INIT_LEVEL 	= HIGHT_LEVEL;
		if(Drv_Gpio_Init(&this->private.drv_gpio_wp) < 0){
			return -1;
		}		
	}

	//reset io config
	if (this->PIN_RESET != NULL)
	{
		this->private.drv_gpio_reset.PIN 			= this->PIN_RESET;
		this->private.drv_gpio_reset.MODE			= OUTPUT_UP;
		this->private.drv_gpio_reset.INIT_LEVEL 	= HIGHT_LEVEL;
		if(Drv_Gpio_Init(&this->private.drv_gpio_reset) < 0){
			return -1;
		}		
	}
	
	this->Read			  						= W25qxxRead;
	this->Write									= W25qxxWriteNoCheck;//W25qxxWrite;
	this->EraseSector							= W25qxxEraseAppointSector;
	this->Check									= W25qxxCheck;
	
#if SPI_DRV_SINGLE_BYTE_READ_WRITE_ENABLE == 1		
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);
	
	this->private.drv_spix.ReadWriteByte(&this->private.drv_spix, 0xFF);
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);
#else
	uint8_t byteRead  = 0;
	uint8_t byteWrite = 0;

	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 0);
	
	byteWrite = 0xFF;	
	this->private.drv_spix.ReadWrite(&(this->private.drv_spix), &byteWrite, &byteRead, 1);   
	
	this->private.drv_gpio_spics.Write(&this->private.drv_gpio_spics, 1);
#endif	
	
	//读取FLASH ID判断是否正确
	if(this->mem_type != W25qxxReadID(this))
		return -1;
	
	return 0;
}
/******************* (C) COPYRIGHT 2020 CIQTEK 陈哲自动化 *****END OF FILE****/
